#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

#define BUFSIZE 32

char file_type(struct stat s)
{
	switch (s.st_mode & S_IFMT) {
		case S_IFBLK:
			return 'b';
		case S_IFCHR:
			return 'c';
		case S_IFDIR:
			return 'd';
		case S_IFIFO:
			return 'p';
		case S_IFLNK:
			return 'l';
		case S_IFREG:
			return '-';
		case S_IFSOCK:
			return 's';
		default:
			return '?';
	}
}

char *file_perm(struct stat s)
{
	int flags[] = {S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH};
	int i;
	static char perm[BUFSIZE] = "rwxrwxrwx";

	for (i = 0; i < 9; i++) {
		if (!(s.st_mode & flags[i])) {
			perm[i] = '-';
		}
	}

	return perm;
}

long int file_nlink(struct stat s)
{
	return s.st_nlink;
}

long int file_size(struct stat s)
{
	return s.st_size;
}

char *file_user_name(uid_t uid)
{
	struct passwd *pw = getpwuid(uid);
	if (NULL == pw)
		return NULL;
	return pw->pw_name;
}

char *file_group_name(gid_t gid)
{
	struct group *gr = getgrgid(gid);
	if (NULL == gr)
		return NULL;
	return gr->gr_name;
}

char *file_time_string(time_t tim)
{
	static char timestr[BUFSIZE] = {'\0'};
	struct tm *local = localtime(&tim);
	
	strftime(timestr, 32, "%m月 %d %H:%M", local);

	return timestr;
}

int main(int argc, char **argv)
{
	struct stat s;

	char type;
	char *perm;
	long int nlink;
	char *uid;
	char *gid;
	long int size;
	char *timestr;

	if (argc < 2) {
		return -1;
	}

	stat(argv[1], &s);

	type = file_type(s);
	perm = file_perm(s);
	nlink = file_nlink(s);
	uid = file_user_name(s.st_uid);
	gid = file_group_name(s.st_gid);
	size = file_size(s);
	timestr = file_time_string(s.st_mtim.tv_sec);

	printf("%c%s %ld %s %s %ld %s %s\n", type, perm, nlink, uid, gid, size, timestr, argv[1]);

	return 0;
}

